package org.com.system.util.dao;

import java.util.List;
import org.com.system.util.model.ActionValues;
import org.com.system.util.model.Dao;
import org.com.system.util.model.Page;
import org.com.system.util.sql.CriteriaGener;
import org.com.system.util.utils.ModelUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Order;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Repository
@Transactional(propagation=Propagation.SUPPORTS,readOnly=true)
public class HibernateDao<E> implements Dao<E> {

	private Session session=null;
	public SessionFactory sessionFactory=null;
	
	public HibernateDao(){}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void save(E entity) {
		session=sessionFactory.getCurrentSession();
		session.saveOrUpdate(entity);
	}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void save(List<E> entitys) {
		session=sessionFactory.getCurrentSession();
		for(E entity:entitys){
			session.saveOrUpdate(entity);
		}
	}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void save(ActionValues<String, Object> values, Class<E> entityClass) {
		Object entity=ModelUtils.copyFromMap(values,entityClass);
		session=sessionFactory.getCurrentSession();
		session.saveOrUpdate(entity);
	}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
    public void save(List<ActionValues<String,Object>> values,Class<E> entityClass){
    	session=sessionFactory.getCurrentSession();
		for(ActionValues<String,Object> value:values){
			Object entity=ModelUtils.copyFromMap(value,entityClass);
			session.saveOrUpdate(entity);
		}
	}
    
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void delete(E entity) {
		session=sessionFactory.getCurrentSession();
		session.delete(entity.getClass().getSimpleName(),entity);
	}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void delete(String id, Class<E> entityClass) {
		session=sessionFactory.getCurrentSession();
		Object entity=session.get(entityClass, id);
		if(null!=entity){
			session.delete(entity);
		}
	}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void delete(ActionValues<String, Object> values, Class<E> entityClass) {
		Object entity=ModelUtils.copyFromMap(values,entityClass);
		session=sessionFactory.getCurrentSession();
		session.delete(entityClass.getSimpleName(),entity);
	}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void delete(List<E> entitys) {
		session=sessionFactory.getCurrentSession();
        for(E entity:entitys){
        	session.delete(entity);
        }
	}
	
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
    public void delete(List<String> ids, Class<E> entityClass) {
    	session=sessionFactory.getCurrentSession();
    	for(String id:ids){
    		Object entity=session.get(entityClass, id);
    		if(null!=entity){
    			session.delete(entity);
    		}
    	}
	}
	
    @SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.SUPPORTS,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
    public E get(ActionValues<String, Object> values, Class<E> entityClass) {
    	E entity=null;
    	session=sessionFactory.getCurrentSession();
    	entity=(E)session.get(entityClass, values.getString("id"));
		return entity;
	}
	
    @SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.SUPPORTS,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public E get(String id, Class<E> entityClass) {
		E entity=null;
		session=sessionFactory.getCurrentSession();
		entity=(E)session.get(entityClass, id);
		return entity;
	}
    
    @SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.SUPPORTS,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public E get(long id, Class<E> entityClass) {
		E entity=null;
		session=sessionFactory.getCurrentSession();
		entity=(E)session.get(entityClass, id);
		return entity;
	}

    @SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.SUPPORTS,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public List<E> list(ActionValues<String,Object> values, Class<E> entityClass) {
		session=sessionFactory.getCurrentSession();
		Criteria criteria=session.createCriteria(entityClass);
		CriteriaGener.process(criteria, values, entityClass);
		List<E> list=criteria.list();
		return list;
	}

    @SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.SUPPORTS,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public List<E> list(ActionValues<String,Object> values,Class<E> entityClass,Page page) {
    	if(null!=page){
    		values.put("page", page);	
    	}else{
    		page=Page.defaultPage;
    	}
    	session=sessionFactory.getCurrentSession();
		Criteria criteria=session.createCriteria(entityClass);
		CriteriaGener.process(criteria, values, entityClass);
		criteria.setFirstResult(page.getPageNow()<=1?0:(page.getPageNow()-1)*page.getPageSize());
		criteria.setMaxResults(page.getPageSize());
		List<E> list=criteria.list();
		return list;
	}
	
    @SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.SUPPORTS,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public List<E> list(Class<E> entityClass) {
    	session=sessionFactory.getCurrentSession();
		Criteria criteria=session.createCriteria(entityClass);
		criteria.addOrder(Order.desc(Page.defaultPage.getOrderby()));
		List<E> list=criteria.list();
		return list;
	}

    @SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.SUPPORTS,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public List<E> list(Class<E> entityClass,Page page) {
    	if(null==page){
    		page=Page.defaultPage;;	
    	}
    	session=sessionFactory.getCurrentSession();
		Criteria criteria=session.createCriteria(entityClass);
		if("asc".equalsIgnoreCase(page.getOrder())){
			criteria.addOrder(Order.asc(page.getOrderby()));
		}else{
			criteria.addOrder(Order.desc(page.getOrderby()));
		}
		criteria.setFirstResult(page.getPageNow()<=1?0:(page.getPageNow()-1)*page.getPageSize());
		criteria.setMaxResults(page.getPageSize());
		List<E> list=criteria.list();
		return list;
	}
    
    @Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void update(E entity) {
    	session=sessionFactory.getCurrentSession();
    	session.update(entity);
	}

    @SuppressWarnings("unchecked")
	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void update(ActionValues<String, Object> values, Class<E> entityClass) {
		session=sessionFactory.getCurrentSession();
		E entity=(E)session.get(entityClass, values.getString("id"));
		values.updateBean(entity, entityClass);
    	session.update(entity);
	}

	@Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void update(List<E> entitys) {
		session=sessionFactory.getCurrentSession();
		for(E entity:entitys){
			session.update(entity);
		}
		
	}
    
	@SuppressWarnings("unchecked")
    @Transactional(propagation=Propagation.REQUIRED,rollbackFor={RuntimeException.class, Exception.class},readOnly=false)
	public void update(List<ActionValues<String,Object>> values,Class<E> entityClass){
    	E entity=null;
    	session=sessionFactory.getCurrentSession();
    	for(ActionValues<String,Object> value:values){
			entity=(E)session.get(entityClass, value.getString("id"));
			value.updateBean(entity, entityClass);
	    	session.update(entity);
		}
	}

	@Required
	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}
	
	public Session getCurrentSession(){
		return sessionFactory.getCurrentSession();
	}

}
